% image file collection on the hard disk drives
classdef ImageFileCollection < handle
	properties
	nImages;
	root;
	database;  % relative paths of images in the database
	preprocessor;
	associatedMotions;  % associated MotionCollection object
	end

	methods
	function obj = ImageFileCollection(varargin)
		p = inputParser;
		addParamValue(p, 'root', '', @isstr);
		addParamValue(p, 'database', {}, @iscell);
		addParamValue(p, 'maxImages', Inf, @isnumeric);
		addParamValue(p, 'preprocessor', @deal, @(x) isa(x, 'function_handle'));
		parse(p, varargin{:});

		obj.root = p.Results.root;
		if isempty(p.Results.database)
			if isempty(obj.root)
				error('Invalid arguments');
			end
			obj.database = retrieveFiles(p.Results.root, 'jpg', 0, ...
				p.Results.maxImages);
		else
			obj.database = p.Results.database;
		end

		obj.nImages = size(obj.database, 1);
		if obj.nImages > p.Results.maxImages
			obj.database = obj.database(1:maxImages);
		end

		obj.preprocessor = p.Results.preprocessor;
	end

	function bw = at(obj, ind)
		imagePath = fullfile(obj.root, obj.database{ind});
		im = imread(imagePath);

		if ~isequal(obj.preprocessor, @deal)
			im = obj.preprocessor(im);
		end

		if ~islogical(im)
			bw = im2bw(im);
		else
			bw = im;
		end

		% NOTE: remove the line below if images have been cropped.
		bw = cropImage(bw);
	end

	function pose = associatedPoseAt(obj, ind)
		imagePath = obj.database{ind};
		matched = regexp(imagePath, ...
			'(?<subject>S\d)\\Mocap_Data\\(?<action_trial>[\w]+)\\C(?<cam>\d+)-(?<frame>\d+)\.', ...
				'names');
		frameID = str2double(matched.frame);
		pose = obj.associatedMotions.getPoseCoord(matched.subject, ...
			matched.action_trial, str2double(matched.cam), frameID);
		% `pose` may be empty, which means this is an invalid frame.
	end

	function [] = deleteInvalidImages(obj)
		assert(~isempty(obj.associatedMotions));
		for i = 1:obj.nImages
			try
				pose = obj.associatedPoseAt(i);
			catch
				pose = [];
			end

			if isempty(pose)
				delete(fullfile(obj.root, obj.database{i}));
			end
		end
	end

	function cachingPath = cachingPathAt(obj, ind)
		imagePath = obj.database{ind};
		cachingPath = fullfile(obj.root, strrep(imagePath, '.jpg', '.cch'));
	end
	end
end